Skip to content

webpack 构建过程

  • 初始化参数:将 shell 和 配置文件中的 参数进行合并,得到最终参数
  • 初始化 compiler :初始化 Compiler 对象,加载所有配置的插件,注册所有的插件
  • 开始编译:开始执行 compire run,
    • 确定入口:从入口 entry 开始分析,
    • 编译模块:调用所有配置的 Loader 对文件进行编译解析,递归找到模块依赖模块,直到所有入口文件都经过处理
    • 输出资源:根据入口和模块的依赖,组装多个包含多个模块的 chunk,把每个 chunk 转化成一个单独文件加入到输出文件列表
    • 文件输出:每个 chunk 包装成一个文件并输出

构建过程简易

  • 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler
  • 编译:从 Entry 出发,针对每个 Module 串行调用对应的 Loader 去翻译文件的内容,再找到该 Module 依赖的 Module,递归地进行编译处理
  • 输出:将编译后的 Module 组合成 Chunk,将 Chunk 转换成文件,输出到文件系统中
js
let fs = require("fs");
let path = require("path");

const { SyncHook } = require("tapable");

class Compiler {
  constructor(options) {
    this.options = options;
    this.hooks = {
      run: new SyncHook(),
      done: new SyncHook(),
    };
  }
  run() {
    this.hooks.run.call();
    let modules = [];
    let chunks = [];
    let files = [];

    // entry 找到入口
    let entry = path.join(this.options.context, this.options.entry);

    // 入口分析,调用配置的 loader 进行编译
    let entryContent = fs.readFileSync(entry, "utf8");
    let entrySource = babelLoader(entryContent);
    let entryModule = { id: entry, source: entrySource };
    modules.push(entryModule);

    //递归找依赖
    let title = path.join(this.options.context, "./src/title.js");
    let titleContent = fs.readFileSync(title, "utf8");
    let titleSource = babelLoader(titleContent);
    let titleModule = { id: title, source: titleSource };
    modules.push(titleModule);

    //根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk
    let chunk = { name: "main", modules };
    chunks.push(chunk);
    //再把每个Chunk转换成一个单独的文件加入到输出列表
    let file = {
      file: this.options.output.filename,
      source: `
(function (modules) {
   function __webpack_require__(moduleId) {
     var module = { exports: {} };
     modules[moduleId].call(
     module.exports,
     module,
     module.exports,
     __webpack_require__
     );
     return module.exports;
   }
   return __webpack_require__("./src/app.js");
 })(
{
 "./src/app.js": function (module, exports, __webpack_require__) {
     var title = __webpack_require__("./src/title.js");
     console.log(title);
 },
 "./src/title.js": function (module) {
     module.exports = "title";
 },
});
`,
    };
    files.push(file);
    //在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
    let outputPath = path.join(
      this.options.output.path,
      this.options.output.filename
    );
    fs.writeFileSync(outputPath, file.source, "utf8");
    this.hooks.done.call();
  }
}

// 获取参数
let options = require("./webpack.config");

// 初始化 compiler
let compiler = new Compiler(options);

// 加载插件
if (options.plugins && Array.isArray(options.plugins)) {
  for (const plugin of options.plugins) {
    plugin.apply(compiler);
  }
}

// 编译
compiler.run();
function babelLoader(source) {
  return `var sum = function sum(a, b) {
              return a + b;
            };`;
}

webpack 如何指定模块化规范(amd、cmd 这些)

libraryTarget: 'umd'

webpack 如何实现的模块依赖关系 traverse ast ImportDeclaration

在 MIT 许可下发布